﻿using System;
using System.Collections.Generic;
using DataStore;
using DataStore.Domain;
using DataStore.Repositories;
using Infrastructure.CurrentData;
using Microsoft.Practices.Composite.Events;
using Infrastructure.Events;
using System.Collections.ObjectModel;
using System.Collections.Specialized;
using System.ComponentModel;
using System.Windows.Input;

namespace Infrastructure.ViewModels
{
    /// <summary>
    /// Person viewmodel
    /// </summary>
    public class PersonViewModel : DataModelSingle<Person>, IDataErrorInfo
    {
        /// <summary>
        /// Occurs when [updated].
        /// </summary>
        public event EventHandler<EventArgs> Updated;
        /// <summary>
        /// Called when [updated].
        /// </summary>
        /// <param name="sender">The sender.</param>
        /// <param name="e">The <see cref="System.EventArgs"/> instance containing the event data.</param>
        protected virtual void OnUpdated(object sender, EventArgs e)
        {
            if(Updated != null)
            {
                Updated(sender, e);
            }
        }

        void SyncObservableCollections()
        {
            // Create email viewmodels
            if (Item.Emails != null)
            {
                foreach (var item in Item.Emails)
                {
                    _emails.Add(new EmailLinkViewModel(item));
                }
            }
            // Sync email modifications
            _emails.CollectionChanged += (object sender, NotifyCollectionChangedEventArgs e) =>
                {
                    switch (e.Action)
                    {
                        case NotifyCollectionChangedAction.Add:
                            if (Item.Emails == null)
                            {
                                Item.Emails = new List<EmailLink>();
                            }
                            foreach (EmailLinkViewModel item in e.NewItems)
                            {
                                Item.Emails.Add(item.Item);
                                OnPropertyChanged("Emails");
                            }
                            break;
                        case NotifyCollectionChangedAction.Move:
                            throw new NotImplementedException();
                            break;
                        case NotifyCollectionChangedAction.Remove:
                            foreach (EmailLinkViewModel item in e.OldItems)
                            {
                                Item.Emails.Remove(item.Item);
                                OnPropertyChanged("Emails");
                            }
                            break;
                        case NotifyCollectionChangedAction.Replace:
                            throw new NotImplementedException();
                            break;
                        case NotifyCollectionChangedAction.Reset:
                            throw new NotImplementedException();
                            break;
                        default:
                            throw new NotImplementedException();
                            break;
                    }
                };

            // Create website viewmodels
            if (Item.Websites != null)
            {
                foreach (var item in Item.Websites)
                {
                    _websites.Add(new LinkViewModel(item));
                }
            }
            // Sync website modifications
            _websites.CollectionChanged += (object sender, NotifyCollectionChangedEventArgs e) =>
                {
                    switch (e.Action)
                    {
                        case NotifyCollectionChangedAction.Add:
                            if (Item.Emails == null)
                            {
                                Item.Emails = new List<EmailLink>();
                            }
                            foreach (EmailLinkViewModel item in e.NewItems)
                            {
                                Item.Emails.Add(item.Item);
                                OnPropertyChanged("Emails");
                            }
                            break;
                        case NotifyCollectionChangedAction.Move:
                            throw new NotImplementedException();
                            break;
                        case NotifyCollectionChangedAction.Remove:

                            break;
                        case NotifyCollectionChangedAction.Replace:
                            throw new NotImplementedException();
                            break;
                        case NotifyCollectionChangedAction.Reset:
                            throw new NotImplementedException();
                            break;
                        default:
                            throw new NotImplementedException();
                            break;
                    }
                };

            // Create image viewmodels
            if (Item.Images != null)
            {
                foreach (var item in Item.Images)
                {
                    _images.Add(new LinkViewModel(item));
                }
            }
            // Sync image modifications
            _images.CollectionChanged += (object sender, NotifyCollectionChangedEventArgs e) =>
                {
                    switch (e.Action)
                    {
                        case NotifyCollectionChangedAction.Add:
                            if (Item.Images == null)
                            {
                                Item.Images = new List<ImageLink>();
                            }
                            foreach (LinkViewModel item in e.NewItems)
                            {
                                //Item.Images.Add(item.Item);
                                OnPropertyChanged("Emails");
                            }
                            break;
                        case NotifyCollectionChangedAction.Move:
                            throw new NotImplementedException();
                            break;
                        case NotifyCollectionChangedAction.Remove:
                            break;
                        case NotifyCollectionChangedAction.Replace:
                            throw new NotImplementedException();
                            break;
                        case NotifyCollectionChangedAction.Reset:
                            throw new NotImplementedException();
                            break;
                        default:
                            throw new NotImplementedException();
                            break;
                    }
                };
        }


        /// <summary>
        /// Initializes a new instance of the <see cref="PersonViewModel"/> class.
        /// </summary>
        /// <param name="person">The person.</param>
        public PersonViewModel(Person person) : base(person)
        {
            SyncObservableCollections();
        }

        /// <summary>
        /// Initializes a new instance of the <see cref="PersonViewModel"/> class.
        /// </summary>
        /// <param name="eventAggregator">The event aggregator.</param>
        /// <param name="person">The person.</param>
        public PersonViewModel(IEventAggregator eventAggregator, Person person) : base(eventAggregator, person)
        {
            SyncObservableCollections();
        }

        /// <summary>
        /// Gets or sets the id.
        /// </summary>
        /// <value>The id.</value>
        public virtual Guid Id
        {
            get
            {
                return Item.Id;
            } 
            set
            {
                Item.Id = value;
                OnPropertyChanged("Id");
            }
        }
        /// <summary>
        /// Gets or sets the full name of the person.
        /// </summary>
        /// <value>The full name.</value>
        public virtual string Name
        {
            get
            {
                return string.Format("{0} {1} {2}", Title, FirstName, LastName);
            }
        }
        /// <summary>
        /// Gets or sets the first name.
        /// </summary>
        /// <value>The first name.</value>
        public virtual string FirstName
        {
            get
            {
                return Item.FirstName;
            }
            set
            {
                if (Item.FirstName != value)
                {
                    Item.FirstName = value;
                }
                OnPropertyChanged("FirstName");
            }
        }
        /// <summary>
        /// Gets or sets the name of the middle.
        /// </summary>
        /// <value>The name of the middle.</value>
        public virtual string MiddleName
        {
            get
            {
                return Item.MiddleName;
            }
            set
            {
                if (Item.MiddleName != value)
                {
                    Item.MiddleName = value;
                }
                OnPropertyChanged("MiddleName");
            }
        }
        /// <summary>
        /// Gets or sets the last name.
        /// </summary>
        /// <value>The last name.</value>
        public virtual string LastName
        {
            get
            {
                return Item.LastName;
            }
            set
            {
                if (Item.LastName != value)
                {
                    Item.LastName = value;
                }
                OnPropertyChanged("LastName");
            }
        }
        /// <summary>
        /// Gets or sets the institution.
        /// </summary>
        /// <value>The institution.</value>
        public virtual ICollection<Company> Institutions { get; set; }

        ObservableCollection<EmailLinkViewModel> _emails = new ObservableCollection<EmailLinkViewModel>();
        /// <summary>
        /// Gets or sets the emails.
        /// </summary>
        /// <value>The emails.</value>
        public virtual ICollection<EmailLinkViewModel> Emails 
        {
            get
            {
                return _emails;
            }
        }

        ObservableCollection<LinkViewModel> _websites = new ObservableCollection<LinkViewModel>();
        /// <summary>
        /// Gets or sets the websites.
        /// </summary>
        /// <value>The websites.</value>
        public virtual ICollection<LinkViewModel> Websites 
        {
            get
            {
                return _websites;
            }
        }

        ObservableCollection<LinkViewModel> _images = new ObservableCollection<LinkViewModel>();
        /// <summary>
        /// Gets or sets the images made about the person.
        /// </summary>
        /// <value>The images.</value>
        public virtual ICollection<LinkViewModel> Images
        {
            get
            {
                return _images;
            }
        }

        
        /// <summary>
        /// Gets or sets the phone numbers.
        /// </summary>
        /// <value>The phone numbers.</value>
        public virtual ICollection<string> PhoneNumbers 
        {
            get
            {
                return Item.PhoneNumbers;
            }
        }

        ObservableCollection<AddressViewModel> _addresses = new ObservableCollection<AddressViewModel>();
        /// <summary>
        /// Gets or sets the addresses.
        /// </summary>
        /// <value>The addresses.</value>
        public virtual ICollection<AddressViewModel> Addresses 
        {
            get
            {
                return _addresses;
            }
        }

        /// <summary>
        /// Gets or sets the comment.
        /// </summary>
        /// <value>The comment.</value>
        public virtual string Comment 
        {
            get
            {
                return Item.Comment;
            }
            set
            {
                if (Item.Comment != value)
                {
                    Item.Comment = value;
                    OnPropertyChanged("Comment");
                }
            }
        }
        /// <summary>
        /// Gets or sets the employment position, job.
        /// </summary>
        /// <value>The position.</value>
        public virtual string Position
        {
            get
            {
                return Item.Position;
            }
            set
            {
                if (Item.Position != value)
                {
                    Item.Position = value;
                }
                OnPropertyChanged("Position");
            }
        }
        /// <summary>
        /// Gets or sets the title.
        /// </summary>
        /// <value>The title.</value>
        public virtual string Title
        {
            get
            {
                return Item.Title;
            }
            set
            {
                if (Item.Title != value)
                {
                    Item.Title = value;
                }
                OnPropertyChanged("Title");
            }
        }

        /// <summary>
        /// Gets a value indicating whether thye entity is a new item.
        /// </summary>
        /// <value>
        /// 	<c>true</c> if the entity is a new item; otherwise, <c>false</c>.
        /// </value>
        protected override bool IsNewItem
        {
            get
            {
                return Item.Id == Guid.Empty;
            }
        }

        /// <summary>
        /// Saves the entity.
        /// </summary>
        public override void Save()
        {
            IDatabase database = Current.Container.Resolve<IDatabase>();
            using (var unitOfWork = database.CreateUnitOfWork())
            {

                try
                {
                    IRepository<Person> repository = new PersonRepository(unitOfWork);
                    unitOfWork.BeginTransaction();
                    repository.SaveOrUpdate(Item);
                    unitOfWork.CommitTransaction();

                    EventAggregator.GetEvent<PersonSavedEvent>().Publish(Item);
                }
                catch
                {
                    unitOfWork.RollbackTransaction();
                    throw;
                }
            }


            OnUpdated(this, EventArgs.Empty);
            base.Save();
        }

        /// <summary>
        /// Gets a value indicating whether this instance can be saved.
        /// </summary>
        /// <value><c>true</c> if this instance can be saved; otherwise, <c>false</c>.</value>
        protected override bool CanSave
        {
            get
            {
                return Item.IsValid;
            }
        }

        /// <summary>
        /// Gets an error message indicating what is wrong with this object.
        /// </summary>
        /// <value></value>
        /// <returns>An error message indicating what is wrong with this object. The default is an empty string ("").</returns>
        public string Error
        {
            get { return (Item as IDataErrorInfo).Error; }
        }

        /// <summary>
        /// Gets the <see cref="System.String"/> with the specified column name.
        /// </summary>
        /// <value></value>
        public string this[string columnName]
        {
            get
            {
                string error = string.Empty;
                error = (Item as IDataErrorInfo)[columnName];

                CommandManager.InvalidateRequerySuggested();
                return error;
            }
        }
    }
}